#include "db_server_connection.h"

#include <google/protobuf/descriptor.h>
using namespace google::protobuf;

#include <protocols/protos/common.pb.h>
using namespace proto::common;
#include <protocols/protos/db.pb.h>
using namespace proto::db;

#include <protocols/protos/common.pb.h>
#include <protocols/protos/db.pb.h>

#include <common/base/server_cfg.h>
#include <common/base/server_mgr.h>
#include <common/base/sub_server_mgr.h>
#include <common/log/log.h>
#include <common/net/message_parse.h>
#include <common/net/session.h>
#include <common/net/session_mgr.h>

bool DbServerConnection::init()
{
    const auto& sessionMgr = ServerMgr::get().getMgr<SessionMgr>(ManagerType::eSession);
    std::vector<std::shared_ptr<Session> > sessions;
    sessionMgr->getConnSessions(ServerType::eDbServer, SessionType::eNormal, sessions);
    if (sessions.empty())
    {
        LOG_ERROR("NO db server connected.");
        return false;
    }
    if (sessions.size() > 1)
    {
        LOG_ERROR("db server only can one, but has more, size is:" << sessions.size());
        return false;
    }
    dbSession_ = sessions[0];
    if (!dbSession_)
    {
        LOG_ERROR("DB sesssion create failed.");
        return false;
    }
    if (!dbSession_->isOpen())
    {
        LOG_ERROR("db Session not open.");
        return false;
    }
    return true;
}

bool DbServerConnection::add(uint32_t playerID, google::protobuf::Message* table,
                             uint16_t retModuleType, uint16_t retMsgID)
{
    std::vector<google::protobuf::Message*> tables;
    tables.push_back(table);
    return add(playerID, tables, retModuleType, retMsgID);

}

bool DbServerConnection::add(uint32_t playerID, const std::vector<google::protobuf::Message*>& tables,
                             uint16_t retModuleType, uint16_t retMsgID)
{
    return dealTables(playerID, tables, proto::db::S2DB_ADD_REQ, retModuleType, retMsgID);
}


bool DbServerConnection::del(uint32_t playerID, google::protobuf::Message* table,
                             uint16_t retModuleType, uint16_t retMsgID)
{
    std::vector<google::protobuf::Message*> tables;
    tables.push_back(table);
    return del(playerID, tables, retModuleType, retMsgID);
}

bool DbServerConnection::del(uint32_t playerID, const std::vector<google::protobuf::Message*>& tables,
                             uint16_t retModuleType, uint16_t retMsgID)
{
    return dealTables(playerID, tables, proto::db::S2DB_DEL_REQ, retModuleType, retMsgID);
}

bool DbServerConnection::update(uint32_t playerID, google::protobuf::Message* table,
                                uint16_t retModuleType, uint16_t retMsgID)
{
    std::vector<google::protobuf::Message*> tables;
    tables.push_back(table);
    return update(playerID, tables, retModuleType, retMsgID);
}


bool DbServerConnection::update(uint32_t playerID, const std::vector<google::protobuf::Message*>& tables,
                                uint16_t retModuleType, uint16_t retMsgID)
{
    return dealTables(playerID, tables, proto::db::S2DB_UPDATE_REQ, retModuleType, retMsgID);
}

bool DbServerConnection::dealTables(uint32_t playerID, const std::vector<google::protobuf::Message*>& tables,
                                    uint16_t reqMsgID,
                                    uint16_t retModuleType, uint16_t retMsgID)
{
    if (!dbSession_)
    {
        LOG_ERROR("No database session was found.");
        return false;
    }
    DbReq req;
    req.set_ret_module_type(retModuleType);
    req.set_ret_msg_id(retMsgID);

    std::string strbuf;
    for (const auto& table : tables)
    {
        auto desc = table->GetDescriptor();
        if (!desc)
        {
            // LOG_ERROR("Message no descriptor, " << table.DebugString());
            return false;
        }

        auto tableInfo = req.add_tables();
        tableInfo->set_table_proto_name(desc->full_name());
        strbuf.clear();
        tableInfo->set_table_buffer(table->SerializeAsString());
    }

    CommonGateReq transReq;
    transReq.set_player_id(playerID);
    transReq.set_msg_id(MessageID(proto::common::eDb, reqMsgID).msgID);

    std::string reqBuf = req.SerializeAsString();
    transReq.set_msg_len(reqBuf.size());
    transReq.set_msg(std::move(reqBuf));

    dbSession_->sendMsg(eCommon, proto::common::C2S_COMMON_GATE_REQ, transReq);
    return true;
}
